package com.yangzc.lion.common.dao;

import java.util.Iterator;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.log4j.Logger;

import com.yangzc.lion.sys.util.StringUtil;

/**
 * 无权限过滤的HQL语句的拼装器。
 * 
 * @author 叶中奇
 * @version 1.0 2006-04-02
 */
public class HQLBuilderImp implements IHQLBuilder {
	private static final Logger logger = Logger.getLogger(HQLBuilderImp.class);
	private static final AtomicLong atomicLong = new AtomicLong(0);

	public HQLWrapper buildQueryHQL(HQLInfo hqlInfo) {
		HQLWrapper hqlWrapper = null;
		if (hqlInfo.getDistinctType() == HQLInfo.DISTINCT_YES)
			hqlWrapper = buildDistinctHQL(hqlInfo, hqlInfo.getWhereBlock());
		else
			hqlWrapper = buildNormalHQL(hqlInfo, hqlInfo.getWhereBlock());
		if (logger.isDebugEnabled()) {
			logger.debug("hql:" + hqlWrapper.getHql());
			Iterator<String> para = hqlWrapper.getParameterMap().keySet()
					.iterator();
			while (para.hasNext()) {
				String key = para.next();
				logger.debug("hql parameter:: name:" + key + " value:"
						+ hqlWrapper.getParameterMap().get(key));
			}
		}
		return hqlWrapper;
	}

	private HQLWrapper buildDistinctHQL(HQLInfo hqlInfo, String extendWhereBlock) {
		StringBuffer hql = new StringBuffer();
		String tempName = "kmss_tmp_" + getNextIndex();
		if (hqlInfo.isGettingCount()) {
			hql.append("select count(distinct " + hqlInfo.getModelTable()
					+ ".fdId) ");
			hql.append("from " + hqlInfo.getModelName() + " "
					+ hqlInfo.getModelTable() + " ");
		} else {
			if (StringUtil.isNull(hqlInfo.getSelectBlock()))
				hql.append("select " + tempName + " ");
			else
				hql.append("select "
						+ replaceTempName(hqlInfo.getSelectBlock(),
								hqlInfo.getModelTable(), tempName) + " ");
			hql.append("from " + hqlInfo.getModelName() + " " + tempName + " ");
			hql.append(replaceTempName(getAutoFetchInfo(hqlInfo),
					hqlInfo.getModelTable(), tempName));
			hql.append("where " + tempName + ".fdId in (");
			hql.append("select " + hqlInfo.getModelTable() + ".fdId ");
			if (StringUtil.isNull(hqlInfo.getFromBlock()))
				hql.append("from " + hqlInfo.getModelName() + " "
						+ hqlInfo.getModelTable() + " ");
			else
				hql.append("from " + hqlInfo.getFromBlock() + " ");
		}

		if (!StringUtil.isNull(hqlInfo.getJoinBlock()))
			hql.append(hqlInfo.getJoinBlock() + " ");

		if (!StringUtil.isNull(extendWhereBlock))
			hql.append("where " + extendWhereBlock);

		if (!hqlInfo.isGettingCount()) {
			hql.append(")");
			if (!StringUtil.isNull(hqlInfo.getOrderBy()))
				hql.append(" order by "
						+ replaceTempName(hqlInfo.getOrderBy(),
								hqlInfo.getModelTable(), tempName));
		}
		return new HQLWrapper(hql.toString(), hqlInfo.getParameterMap());
	}

	private HQLWrapper buildNormalHQL(HQLInfo hqlInfo, String extendWhereBlock) {
		StringBuffer hql = new StringBuffer();
		if (hqlInfo.isGettingCount()) {
			hql.append("select count(*) ");
			hql.append("from " + hqlInfo.getModelName() + " "
					+ hqlInfo.getModelTable() + " ");
		} else {
			if (StringUtil.isNull(hqlInfo.getSelectBlock()))
				hql.append("select " + hqlInfo.getModelTable() + " ");
			else
				hql.append("select " + hqlInfo.getSelectBlock() + " ");

			if (StringUtil.isNull(hqlInfo.getFromBlock()))
				hql.append("from " + hqlInfo.getModelName() + " "
						+ hqlInfo.getModelTable() + " ");
			else
				hql.append("from " + hqlInfo.getFromBlock() + " ");
			hql.append(getAutoFetchInfo(hqlInfo));
		}

		if (!StringUtil.isNull(hqlInfo.getJoinBlock()))
			hql.append(hqlInfo.getJoinBlock() + " ");

		if (!StringUtil.isNull(extendWhereBlock))
			hql.append("where " + extendWhereBlock + " ");

		if (!hqlInfo.isGettingCount()
				&& !StringUtil.isNull(hqlInfo.getOrderBy()))
			hql.append("order by " + hqlInfo.getOrderBy());
		return new HQLWrapper(hql.toString(), hqlInfo.getParameterMap());
	}

	private String replaceTempName(String srcName, String fromName,
			String toName) {
		return srcName.replaceAll("(^|\\W)" + fromName + "(\\.|\\W)", "$1"
				+ toName + "$2");
	}

	private long getNextIndex() {
		atomicLong.compareAndSet(10000, 0); // 如果累加到了10000，重置为0
		return atomicLong.getAndIncrement();
	}

	private String getAutoFetchInfo(HQLInfo hqlInfo) {
		if (!hqlInfo.isAutoFetch())
			return "";
		if (StringUtil.isNull(hqlInfo.getOrderBy()))
			return "";
		String[] info = hqlInfo.getOrderBy().split("[^A-Za-z0-9_\\.]+");
		StringBuffer rtnVal = new StringBuffer();
		for (int i = 0; i < info.length; i++) {
			info[i] = info[i].trim();
			if (info[i].length() == 0)
				continue;
			int j = info[i].indexOf(" ");
			if (j > -1)
				info[i] = info[i].substring(0, j);
			String[] infoArr = info[i].split("\\.");
			info[i] = infoArr[0];
			for (j = 1; j < infoArr.length - 1; j++) {
				info[i] = info[i] + "." + infoArr[j];
				rtnVal.append("left join fetch " + info[i] + " ");
			}
		}
		return rtnVal.toString();
	}

}
